package cmp.compile;

/***********************************************
 * Almost everything is checked before calling this routine,
 * but checked again just to make sure
 */
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import util.Debug.ErrorReport;
import cmp.main.Globals;
import assem.DBConn;
import cmp.compile.panels.CompilePanel;

public class LoadAAfiles {
	private static final long COMMIT_INTERVAL = 1000;
	
	LoadAAfiles (DBConn dbc, CompilePanel panel, HashMap <String, Integer> ut) {
		cmpDBC = dbc;
		cmpPanel = panel;
		utMap = ut;
		
		CompileMain.PrtDateMsg("\nLoading " + cmpPanel.getAssemblyCount() + " AAfiles");
  		long startTime = CompileMain.getTime();
  		
		try {				
			for (int idx=0; idx< cmpPanel.getAssemblyCount(); idx++)
			{
				if (cmpPanel.getSpeciesPanel().isGenerateProteinFileAt(idx))
					runESTscan(idx);
				loadAAfile(idx);
			}
			CompileMain.PrtSpMsgTime(1, "Complete AA load ", startTime);
		}
		catch (Exception e) {ErrorReport.die(e, "Loading AA files");}
	}
	/*******************************************************************
	* Call ESTscan to make the AA file for project #index in the table
	********************************************************************/
	private void runESTscan(int index) {
	try {
		ResultSet rs;
		
		File ESTDir = new File(Globals.Compile.ESTScanDir);
		File ESTScan = new File(Globals.Compile.ESTScanExec);
		if (!ESTScan.exists())
		{
			CompileMain.die("Cannot find ESTScan at " + ESTScan.getAbsolutePath());
		}

		String smat = cmpPanel.getAssemblySMATFile(index);
		File smatFile = new File(smat);
		if (!smatFile.exists()) CompileMain.die("Cannot find smat file " + smat);
		
		File projDir = new File(cmpPanel.getCurrentProjectDirectory());
		File AAdir = new File(projDir, Globals.Compile.AAfiles);
		if (!AAdir.exists()) AAdir.mkdir();

		String aName = cmpPanel.getAssemblyName(index);
		File pepFile =  new File(AAdir,aName+"_pepES.fasta");
		if (pepFile.exists()) pepFile.delete();

		File nucFile = new File(ESTDir,"estscan.nuc");
		if (nucFile.exists()) nucFile.delete();
			
		CompileMain.PrtSpMsg(2, "Run ESTscan for " + aName);

		File utFile = new File(ESTDir,aName+"_ut2estscan.fasta");
		if (utFile.exists()) utFile.delete();
		BufferedWriter bw = new BufferedWriter(new FileWriter(utFile));
		
		rs = cmpDBC.executeQuery("select utstr,ntseq from unitrans join assembly on unitrans.asmid=assembly.asmid " +
				" where assembly.asmstr='" + aName + "'");
	
		while (rs.next())
		{
			String name = rs.getString(1);
			String seq = rs.getString(2);
			
			bw.write(">" + name + "\n");
			for (int i = 0; i < seq.length(); i += 50)
			{
				int end = Math.min(i+50, seq.length()-1);
				bw.write(seq.substring(i, end));
				bw.newLine();
			}
		}
		bw.close();
		
		String cmd = Globals.Compile.ESTScanExec + " -M " + smatFile.getAbsolutePath() + " -o "+ nucFile.getAbsolutePath() + 
		" -t " + pepFile.getAbsolutePath() + " " + utFile.getAbsolutePath();
		Process p = Runtime.getRuntime().exec(cmd);
		p.waitFor();

		utFile.delete();
		nucFile.delete();

		if (pepFile.exists() )
		{
			cmpPanel.getSpeciesPanel().setProteinFileAt(index,pepFile.getAbsolutePath());
		}
		else
		{	
			System.out.println(cmd);
			CompileMain.die("ESTscan failed to generate peptide file");
		}
	}catch(Exception e){
		ErrorReport.die(e, "running ESTscan"); }
	}

	/*****************************************************
	 * Loads amino acid sequences into existing records
	 * and creates COMBINEDFASTA
	 */
	private void loadAAfile(int idx) {
	try {
		Pattern fasta = Pattern.compile(">(\\S+)"); // can have '.' in name, e.g. xxx.f			
		String prefix = cmpPanel.getAssemblyPrefix(idx);
		String fileName = cmpPanel.getAssemblyProteinFile(idx);	
		
		if (fileName.contains(Globals.PROTEINsTCW)) return;
		
		File file =  new File (fileName);
		if (!file.exists()) {
			fileName = cmpPanel.getCurrentProjectDirectory() + "/" + fileName;

			file =  new File (fileName);
			if (!file.exists()) {
				CompileMain.PrtError("Missing protein file for " + 
						fileName + " for dataset " + cmpPanel.getAssemblyName(idx));
				return;
			}
		}
						
		CompileMain.PrtSpMsg(2, "Load " + file.toString());
	
		BufferedReader reader = new BufferedReader ( new FileReader ( file ) );
		String line, aaSeq=null, UTstr=null;
		int asmID=0, count=0, bad=0;
		boolean first=true;

	    	while ((line = reader.readLine()) != null) 
	    	{
				if(count % COMMIT_INTERVAL == 0) {
					//cmpDBC.commitChanges();
					System.out.print("      Loading AA sequences " + count + "    \r");
				}
				if ( line.length() == 0 || line.charAt(0) == '#' ) continue;  	
	
				String [] tok = line.split(";"); // ESTscan puts ';' after name, e.g. >xxx; 
				Matcher m = fasta.matcher(tok[0]);
					
				// existing record, reading AA sequence
				if (! m.find()) {	
					aaSeq += line; 
					continue;
				}
	
				// new record, first finish last AA
				if (aaSeq!=null) { 
					if (utMap.containsKey(UTstr)) 
					{
						int index = utMap.get(UTstr);
						cmpDBC.executeUpdate("UPDATE unitrans SET " +
							" aaSeq=" + quote(aaSeq) + ", aaLen=" + aaSeq.length() +
							" WHERE UTid=" + index);
						if (first) {
							ResultSet rs = cmpDBC.executeQuery("SELECT ASMid from unitrans " +
										"where UTid=" + index);
							rs.next();
							asmID = rs.getInt(1);
							first=false;
						}
					}
					else {
						if (bad < 5)
							  CompileMain.PrtWarn("File contains sequence identifer not in database '" 
									+ UTstr + "'");
						else if (bad==5) 
								CompileMain.PrtWarn("Surpressing further such error messages");
						bad++;
						if (bad>10 && count==0) 
								CompileMain.die("Too many bad indentifiers and no good ones -- check file");
					}
				}
					
				// new record
				UTstr = m.group(1); 
				aaSeq = "";
				count++;
			} // end while loop through AAfile
	    	
			if (aaSeq!=null) {
				cmpDBC.executeUpdate("UPDATE unitrans SET " +
					" aaSeq=" + quote(aaSeq) + ", aaLen=" + aaSeq.length() +
					" WHERE UTstr=" + quote(UTstr));
			}
			if (asmID!=0 && count !=0) {
				cmpDBC.executeUpdate("UPDATE assembly SET nPep=" + count +
					" WHERE ASMid=" + asmID);
			}
			else CompileMain.PrtWarn("No database for file " + file); // blank file?
			
			//cmpDBC.commitChanges();
			
			CompileMain.PrtSpMsg(3, "AA sequences loaded " + count);
			if (bad>0) CompileMain.PrtSpMsg(3, "IDs not in the database " + bad);
				
		} catch(Exception e) {ErrorReport.die(e, "loading AA files");}
	}

	private String quote(String word) {
		return "\"" + word + "\""; 
	}
	CompilePanel cmpPanel;
	DBConn cmpDBC;	
	HashMap <String, Integer> utMap;
}
